﻿using StackExchange.Redis;
using System;
using System.Collections.Generic;
using System.Linq;

namespace gt.rediscachemanager.Entry
{

    public class EMRedisMessage
    {
        public EMRedisMessage()
        {
        }
        public TimeSpan? ExpiredTime { get; set; }
        public When When { get; set; }
        public EMRedisResult Result { get; set; }

        public RedisKey Key { get; set; }
        public RedisKey[] Keys { get; set; }

        public RedisValue CommonValue { get; set; }

        public ScanValue ScanValue { get; set; }

        public EMStringValue StringValue { get; set; }

        public EMHashValue HashValue { get; set; }

        public EMListValue ListValue { get; set; }

        public EMSetValue SetValue { get; set; }

        public EMSortedSetValue SortedSetValue { get; set; }

        public EMHyperLogLogValue HyperLogLogValue { get; set; }

        public EMBitValue BitValue { get; set; }

        public virtual CommandFlags GetCommandFlags(RedisCommand command)
        {
            switch (command)
            {
                case RedisCommand.HashExist:
                case RedisCommand.HashGet:
                case RedisCommand.HashGetAll:
                case RedisCommand.HashGetByArray:
                case RedisCommand.HashLength:
                case RedisCommand.HashValues:
                case RedisCommand.HashFields:
                case RedisCommand.KeyExists:
                case RedisCommand.ListGetByIndex:
                case RedisCommand.ListLength:
                case RedisCommand.ListRange:
                case RedisCommand.StringGet:
                case RedisCommand.SetLength:
                case RedisCommand.SetMembers:
                case RedisCommand.SetRandomMember:
                case RedisCommand.SetRandomMembers:
                case RedisCommand.SetContains:
                case RedisCommand.SortedSetLength:
                case RedisCommand.SortedSetRangeByRank:
                case RedisCommand.SortedSetRangeByScore:
                case RedisCommand.StringBitCount:
                case RedisCommand.StringBitPosition:
                case RedisCommand.StringGetBit:
                case RedisCommand.HyperLogLogLength:
                case RedisCommand.HyperLogLogLengthArray:
                    return CommandFlags.PreferSlave;
                default:
                    return CommandFlags.DemandMaster;
            }
        }
    }

    public class EMRedisResult
    {
        public EMRedisResult() { }
        public static EMRedisResult Create(string result)
        {
            return new EMRedisResult { InfoResult = result };
        }
        public static EMRedisResult Create(bool result)
        {
            return new EMRedisResult { BoolResult = result };
        }
        public static EMRedisResult Create(long result)
        {
            return new EMRedisResult { LongResult = result };
        }
        public static EMRedisResult Create(double result)
        {
            return new EMRedisResult { DoubleResult = result };
        }
        public static EMRedisResult Create(RedisValue result)
        {
            return new EMRedisResult { RedisValueResult = result };
        }
        public static EMRedisResult Create(RedisValue[] result)
        {
            return new EMRedisResult { RedisValueArrayResult = result };
        }
        public static EMRedisResult Create(HashEntry result)
        {
            return new EMRedisResult { HashEntryResult = result };
        }
        public static EMRedisResult Create(HashEntry[] result)
        {
            return new EMRedisResult { HashEntryArrayResult = result };
        }
        public static EMRedisResult Create(IEnumerable<HashEntry> result)
        {
            return new EMRedisResult { HashEntryScanValue = result };
        }
        public static EMRedisResult Create(IEnumerable<RedisValue> result)
        {
            return new EMRedisResult { RedisScanValue = result };
        }
        public static EMRedisResult Create(TimeSpan? result)
        {
            return new EMRedisResult { TimeSpanResult = result };
        }
        public static EMRedisResult Create(SortedSetEntry result)
        {
            return new EMRedisResult { SortedSetEntryResult = result };
        }
        public static EMRedisResult Create(SortedSetEntry[] result)
        {
            return new EMRedisResult { SortedSetEntryArrayResult = result };
        }
        public static EMRedisResult Create(ClientInfo[] result)
        {
            return new EMRedisResult { ClientInfoArrayResult = result };
        }

        public string InfoResult { get; set; }
        public bool BoolResult { get; set; }
        public long LongResult { get; set; }
        public double DoubleResult { get; set; }
        public RedisValue RedisValueResult { get; set; }
        public RedisValue[] RedisValueArrayResult { get; set; }
        public HashEntry HashEntryResult { get; set; }
        public HashEntry[] HashEntryArrayResult { get; set; }
        public IEnumerable<HashEntry> HashEntryScanValue { get; set; }
        public IEnumerable<RedisValue> RedisScanValue { get; set; }
        public TimeSpan? TimeSpanResult { get; set; }
        public SortedSetEntry SortedSetEntryResult { get; set; }
        public SortedSetEntry[] SortedSetEntryArrayResult { get; set; }
        public ClientInfo[] ClientInfoArrayResult { get; set; }
    }

    //public class RedisMessage<T, TResult>
    //{
    //    private RedisKey m_key;
    //    private TResult m_result;
    //    private T m_value;
    //    private TimeSpan? m_expiredTime;
    //    private When m_when;
    //    private ScanValue m_scan;

    //    public RedisKey Key
    //    {
    //        get { return this.m_key; }
    //        set { this.m_key = value; }
    //    }
    //    public T Value
    //    {
    //        get { return this.m_value; }
    //        set { this.m_value = value; }
    //    }
    //    public TResult Result
    //    {
    //        get { return this.m_result; }
    //        set { this.m_result = value; }
    //    }
    //    public TimeSpan? ExpiredTime
    //    {
    //        get { return this.m_expiredTime; }
    //        set { this.m_expiredTime = value; }
    //    }
    //    public When When
    //    {
    //        get { return this.m_when; }
    //        set { this.m_when = value; }
    //    }
    //    public ScanValue Scan
    //    {
    //        get { return this.m_scan; }
    //        set { this.m_scan = value; }
    //    }

    //    public virtual CommandFlags GetCommandFlags(RedisCommand command)
    //    {
    //        switch (command)
    //        {
    //            case RedisCommand.HashExist:
    //            case RedisCommand.HashGet:
    //            case RedisCommand.HashGetAll:
    //            case RedisCommand.HashGetByArray:
    //            case RedisCommand.HashLength:
    //            case RedisCommand.HashValues:
    //            case RedisCommand.HashFields:
    //            case RedisCommand.KeyExists:
    //            case RedisCommand.ListGetByIndex:
    //            case RedisCommand.ListLength:
    //            case RedisCommand.ListRange:
    //            case RedisCommand.StringGet:
    //            case RedisCommand.SetLength:
    //            case RedisCommand.SetMembers:
    //            case RedisCommand.SetRandomMember:
    //            case RedisCommand.SetRandomMembers:
    //            case RedisCommand.SetContains:
    //            case RedisCommand.SortedSetLength:
    //            case RedisCommand.SortedSetRangeByRank:
    //            case RedisCommand.SortedSetRangeByScore:
    //            case RedisCommand.StringBitCount:
    //            case RedisCommand.StringBitPosition:
    //            case RedisCommand.StringGetBit:
    //            case RedisCommand.HyperLogLogLength:
    //            case RedisCommand.HyperLogLogLengthArray:
    //                return CommandFlags.PreferSlave;
    //            default:
    //                return CommandFlags.DemandMaster;
    //        }
    //    }
    //}

    #region Server

    public class ScanValue
    {
        public ScanValue(string fieldPattern, int pageSize, long cursor, int pageOffset)
        {
            this.FieldPattern = fieldPattern;
            this.Cursor = cursor;
            this.PageSize = pageSize;
            this.PageOffset = pageOffset;
        }
        public string FieldPattern { get; set; }
        public int PageSize { get; set; }

        public long Cursor { get; set; }
        public int PageOffset { get; set; }
    }
    public class LockTakeMessage : EMRedisMessage
    {
        public LockTakeMessage(RedisKey key, RedisValue value, TimeSpan expiredTime)
        {
            this.Key = key;
            this.CommonValue = value;
            this.ExpiredTime = expiredTime;
        }
    }
    public class LockQueryMessage : EMRedisMessage
    {
        public LockQueryMessage(RedisKey key)
        {
            this.Key = key;
        }
    }
    public class LockReleaseMessage : EMRedisMessage
    {
        public LockReleaseMessage(RedisKey key, RedisValue value)
        {
            this.Key = key;
            this.CommonValue = value;
        }
    }

    public class RedisInfoMessage : EMRedisMessage
    {
        public RedisInfoMessage(string value)
        {
            this.CommonValue = value;
        }
    }
    public class ClientListMessage : EMRedisMessage
    {
        public ClientListMessage(string value)
        {
            this.CommonValue = value;
        }
    }

    #endregion

    #region String

    public class EMStringValue
    {
        public RedisValue Value { get; set; }
        public KeyValuePair<RedisKey, RedisValue>[] KeyValues { get; set; }
        public long IncrOrDecrValue { get; set; }
    }
    public class StringSetMessage : EMRedisMessage
    {
        public StringSetMessage(RedisKey key, RedisValue value)
            : this(key, value, null, When.Always)
        { }
        public StringSetMessage(RedisKey key, RedisValue value, TimeSpan? expiredTime)
            : this(key, value, expiredTime, When.Always)
        { }
        public StringSetMessage(RedisKey key, RedisValue value, TimeSpan? expiredTime, When when)
        {
            this.Key = key;
            this.StringValue = new EMStringValue { Value = value };
            this.ExpiredTime = expiredTime;
            this.When = when;
        }
    }
    public class StringAppendMessage : EMRedisMessage
    {
        public StringAppendMessage(RedisKey key, RedisValue value)
        {
            this.Key = key;
            this.StringValue = new EMStringValue { Value = value };
        }
    }
    public class StringSetArrayMessage : EMRedisMessage
    {
        public StringSetArrayMessage(KeyValuePair<RedisKey, RedisValue>[] kvps, When when)
        {
            this.Key = kvps.First().Key;
            this.StringValue = new EMStringValue { KeyValues = kvps };
            this.When = when;
        }
    }
    public class StringGetSetMessage : EMRedisMessage
    {
        public StringGetSetMessage(RedisKey key, RedisValue value)
        {
            this.Key = key;
            this.StringValue = new EMStringValue { Value = value };
        }
    }
    public class StringGetMessage : EMRedisMessage
    {
        public StringGetMessage(RedisKey key)
        {
            this.Key = key;
        }
    }
    public class StringIncrementMessage : EMRedisMessage
    {
        public StringIncrementMessage(RedisKey key, long incrValue)
        {
            this.Key = key;
            this.StringValue = new EMStringValue { IncrOrDecrValue = incrValue };
        }
    }

    #endregion

    #region Key

    public class KeyExistsMessage : EMRedisMessage
    {
        public KeyExistsMessage(RedisKey key)
        {
            this.Key = key;
        }
    }
    public class KeyRemoveMessage : EMRedisMessage
    {
        public KeyRemoveMessage(RedisKey key)
        {
            this.Key = key;
        }
    }
    public class KeyRemoveArrayMessage : EMRedisMessage
    {
        public KeyRemoveArrayMessage(RedisKey[] keys)
        {
            this.Key = keys.FirstOrDefault();
            this.Keys = keys;
        }
    }
    public class KeyExpiredMessage : EMRedisMessage
    {
        public KeyExpiredMessage(RedisKey key, TimeSpan? expiredTime)
        {
            this.Key = key;
            this.ExpiredTime = expiredTime;
        }
    }
    public class KeyTimeToLiveMessage : EMRedisMessage
    {
        public KeyTimeToLiveMessage(RedisKey key)
        {
            this.Key = key;
        }
    }


    #endregion

    #region Hash

    public class EMHashValue
    {
        public RedisValue Field { get; set; }
        public RedisValue[] Fields { get; set; }
        public RedisValue Value { get; set; }
        //public HashEntry HashEntry { get; set; }
        public HashEntry[] HashEntries { get; set; }
        public long IncrOrDecrValue { get; set; }
    }
    public class HashGetMessage : EMRedisMessage
    {
        public HashGetMessage(RedisKey key, RedisValue field)
        {
            this.Key = key;
            this.HashValue = new EMHashValue { Field = field };
        }
    }
    public class HashGetByArrayMessage : EMRedisMessage
    {
        public HashGetByArrayMessage(RedisKey key, RedisValue[] fields)
        {
            this.Key = key;
            this.HashValue = new EMHashValue { Fields = fields };
        }
    }
    public class HashGetAllMessage : EMRedisMessage
    {
        public HashGetAllMessage(RedisKey key)
        {
            this.Key = key;
        }
    }
    public class HashExistsMessage : EMRedisMessage
    {
        public HashExistsMessage(RedisKey key, RedisValue field)
        {
            this.Key = key;
            this.HashValue = new EMHashValue { Field = field };
        }
    }

    public class HashSetMessage : EMRedisMessage
    {
        public HashSetMessage()
        { }
        public HashSetMessage(RedisKey key, RedisValue field, RedisValue value)
            : this(key, field, value, When.Always)
        {
        }
        public HashSetMessage(RedisKey key, RedisValue field, RedisValue value, When when)
        {
            this.Key = key;
            this.HashValue = new EMHashValue { Field = field, Value = value };
            this.When = when;
        }
    }
    public class HashSetArrayMessage : EMRedisMessage
    {
        public HashSetArrayMessage(RedisKey key, HashEntry[] hashEntries)
        {
            this.Key = key;
            this.HashValue = new EMHashValue { HashEntries = hashEntries };
        }
    }
    public class HashRemoveMessage : EMRedisMessage
    {
        public HashRemoveMessage(RedisKey key, RedisValue field)
        {
            this.Key = key;
            this.HashValue = new EMHashValue { Field = field };
        }
    }
    public class HashRemoveArrayMessage : EMRedisMessage
    {
        public HashRemoveArrayMessage(RedisKey key, RedisValue[] fields)
        {
            this.Key = key;
            this.HashValue = new EMHashValue { Fields = fields };
        }
    }
    public class HashScanMessage : EMRedisMessage
    {
        public HashScanMessage(RedisKey key, RedisValue fieldPattern, int pageSize, long cursor, int pageOffset)
        {
            this.Key = key;
            this.ScanValue = new ScanValue(fieldPattern, pageSize, cursor, pageOffset);
        }
    }
    public class HashIncrementMessage : EMRedisMessage
    {
        public HashIncrementMessage(RedisKey key, RedisValue field, long incrValue)
        {
            this.Key = key;
            this.HashValue = new EMHashValue { Field = field, IncrOrDecrValue = incrValue };
        }
    }

    public class HashFieldsMessage : EMRedisMessage
    {
        public HashFieldsMessage(RedisKey key)
        {
            this.Key = key;
        }
    }

    public class HashValuesMessage : EMRedisMessage
    {
        public HashValuesMessage(RedisKey key)
        {
            this.Key = key;
        }
    }

    public class HashLengthMessage : EMRedisMessage
    {
        public HashLengthMessage(RedisKey key)
        {
            this.Key = key;
        }
    }

    #endregion

    #region List

    public class EMListValue
    {
        public long Index { get; set; }
        public long FirstIndex { get; set; }
        public long SecondIndex { get; set; }
        public RedisValue Pivot { get; set; }
        public RedisValue Value { get; set; }
        public long Count { get; set; }
    }

    public class ListGetMessage : EMRedisMessage
    {
        public ListGetMessage(RedisKey key, int index)
        {
            this.Key = key;
            this.ListValue = new EMListValue { Index = index };
        }
    }
    public class ListInsertAfterMessage : EMRedisMessage
    {
        public ListInsertAfterMessage(RedisKey key, RedisValue pivot, string value)
        {
            this.Key = key;
            this.ListValue = new EMListValue { Pivot = pivot, Value = value };
        }
    }
    public class ListInsertBeforeMessage : EMRedisMessage
    {
        public ListInsertBeforeMessage(RedisKey key, RedisValue pivot, RedisValue value)
        {
            this.Key = key;
            this.ListValue = new EMListValue { Pivot = pivot, Value = value };
        }
    }
    public class ListLeftPopMessage : EMRedisMessage
    {
        public ListLeftPopMessage(RedisKey key)
        {
            this.Key = key;
        }
    }
    public class ListLeftPushMessage : EMRedisMessage
    {
        public ListLeftPushMessage(RedisKey key, RedisValue value, When when)
        {
            this.Key = key;
            this.ListValue = new EMListValue { Value = value };
            this.When = when;
        }
    }
    public class ListLengthMessage : EMRedisMessage
    {
        public ListLengthMessage(RedisKey key)
        {
            this.Key = key;
        }
    }
    public class ListRangeMessage : EMRedisMessage
    {
        public ListRangeMessage(RedisKey key, long startIndex, long endIndex)
        {
            this.Key = key;
            this.ListValue = new EMListValue { FirstIndex = startIndex, SecondIndex = endIndex };
        }
    }
    public class ListRightPopMessage : EMRedisMessage
    {
        public ListRightPopMessage(RedisKey key)
        {
            this.Key = key;
        }
    }
    public class ListRightPushMessage : EMRedisMessage
    {
        public ListRightPushMessage(RedisKey key, RedisValue value, When when)
        {
            this.Key = key;
            this.ListValue = new EMListValue { Value = value };
            this.When = when;
        }
    }
    public class ListSetByIndexMessage : EMRedisMessage
    {
        public ListSetByIndexMessage(RedisKey key, RedisValue value, long index)
        {
            this.Key = key;
            this.ListValue = new EMListValue { Index = index, Value = value };
        }
    }
    public class ListTrimMessage : EMRedisMessage
    {
        public ListTrimMessage(RedisKey key, long startIndex, long stopIndex)
        {
            this.Key = key;
            this.ListValue = new EMListValue { FirstIndex = startIndex, SecondIndex = stopIndex };
        }
    }
    public class ListRemoveMessage : EMRedisMessage
    {
        public ListRemoveMessage(RedisKey key, RedisValue value, long count)
        {
            this.Key = key;
            this.ListValue = new EMListValue { Value = value, Count = count };
        }
    }

    #endregion

    #region Set

    public class EMSetValue
    {
        public SetOperation Operation { get; set; }
        public RedisKey Source { get; set; }
        public RedisKey First { get; set; }
        public RedisKey Second { get; set; }
        public RedisKey Destination { get; set; }
        public RedisKey[] Keys { get; set; }
        public RedisValue Value { get; set; }
        public RedisValue[] Values { get; set; }
        public long Count { get; set; }
    }
    public class SetAddMessage : EMRedisMessage
    {
        public SetAddMessage(RedisKey key, RedisValue value)
        {
            this.Key = key;
            this.SetValue = new EMSetValue { Value = value };
        }
    }
    public class SetAddArrayMessage : EMRedisMessage
    {
        public SetAddArrayMessage(RedisKey key, RedisValue[] values)
        {
            this.Key = key;
            this.SetValue = new EMSetValue { Values = values };
        }
    }

    public class SetCombineMessage : EMRedisMessage
    {
        public SetCombineMessage(SetOperation operation, RedisKey first, RedisKey second)
        {
            this.Key = first;
            this.SetValue = new EMSetValue { Operation = operation, First = first, Second = second };
        }
    }
    public class SetCombineArrayMessage : EMRedisMessage
    {
        public SetCombineArrayMessage(SetOperation operation, RedisKey[] keys)
        {
            this.Key = keys.FirstOrDefault();
            this.SetValue = new EMSetValue() { Operation = operation, Keys = keys };
        }
    }
    public class SetCombineAndStoreArrayMessage : EMRedisMessage
    {
        public SetCombineAndStoreArrayMessage(SetOperation operation, RedisKey destination, RedisKey[] keys)
        {
            this.Key = destination;
            this.SetValue = new EMSetValue { Operation = operation, Destination = destination, Keys = keys };
        }
    }
    public class SetCombineAndStoreMessage : EMRedisMessage
    {
        public SetCombineAndStoreMessage(SetOperation opeation, RedisKey destination, RedisKey first, RedisKey second)
        {
            this.Key = destination;
            this.SetValue = new EMSetValue { Operation = opeation, Destination = destination, First = first, Second = second };
        }
    }
    public class SetContainsMessage : EMRedisMessage
    {
        public SetContainsMessage(RedisKey key, RedisValue value)
        {
            this.Key = key;
            this.SetValue = new EMSetValue { Value = value };
        }
    }
    public class SetLengthMessage : EMRedisMessage
    {
        public SetLengthMessage(RedisKey key)
        {
            this.Key = key;
        }
    }
    public class SeMembersMessage : EMRedisMessage
    {
        public SeMembersMessage(RedisKey key)
        {
            this.Key = key;
        }
    }
    public class SetMoveMessage : EMRedisMessage
    {
        public SetMoveMessage(RedisKey source, RedisKey destination, RedisValue value)
        {
            this.Key = source;
            this.SetValue = new EMSetValue { Source = source, Destination = destination, Value = value };
        }
    }
    public class SetPopMessage : EMRedisMessage
    {
        public SetPopMessage(RedisKey key)
        {
            this.Key = key;
        }
    }
    public class SetRandomMemeberMessage : EMRedisMessage
    {
        public SetRandomMemeberMessage(RedisKey key)
        {
            this.Key = key;
        }
    }
    public class SetRandomMembersMessage : EMRedisMessage
    {
        public SetRandomMembersMessage(RedisKey key, long count)
        {
            this.Key = key;
            this.SetValue = new EMSetValue { Count = count };
        }
    }
    public class SetRemoveArrayMessage : EMRedisMessage
    {
        public SetRemoveArrayMessage(RedisKey key, RedisValue[] values)
        {
            this.Key = key;
            this.SetValue = new EMSetValue { Values = values };
        }
    }
    public class SetRemoveMessage : EMRedisMessage
    {
        public SetRemoveMessage(RedisKey key, RedisValue value)
        {
            this.Key = key;
            this.SetValue = new EMSetValue { Value = value };
        }
    }

    #endregion

    #region SortedSet

    public class EMSortedSetValue
    {
        public RedisValue Member { get; set; }
        public double Score { get; set; }
        public double IncreOrDecreValue { get; set; }
        public double Min { get; set; }
        public double Max { get; set; }
        public Exclude Exclude { get; set; }

        public long Start { get; set; }
        public long Stop { get; set; }
        public Order Order { get; set; }

        public double ScoreStart { get; set; }
        public double ScoreStop { get; set; }
        public long Skip { get; set; }
        public long Take { get; set; }
    }

    public class SortedSetAddMessage : EMRedisMessage
    {
        public SortedSetAddMessage(string key, string member, double score, When when)
        {
            this.Key = key;
            this.SortedSetValue = new EMSortedSetValue { Member = member, Score = score };
            this.When = when;
        }
    }
    public class SortedSetDecrementMessage : EMRedisMessage
    {
        public SortedSetDecrementMessage(string key, string member, double value)
        {
            this.Key = key;
            this.SortedSetValue = new EMSortedSetValue { Member = member, IncreOrDecreValue = value };
        }
    }
    public class SortedSetIncrementMessage : EMRedisMessage
    {
        public SortedSetIncrementMessage(string key, string member, double value)
        {
            this.Key = key;
            this.SortedSetValue = new EMSortedSetValue { Member = member, IncreOrDecreValue = value };
        }
    }
    public class SortedSetLengthMessage : EMRedisMessage
    {
        public SortedSetLengthMessage(string key, double min, double max, Exclude exclude)
        {
            this.Key = key;
            this.SortedSetValue = new EMSortedSetValue { Min = min, Max = max, Exclude = exclude };
        }
    }
    public class SortedSetRangeByRankMessage : EMRedisMessage
    {
        public SortedSetRangeByRankMessage(string key, long start, long stop, Order order)
        {
            this.Key = key;
            this.SortedSetValue = new EMSortedSetValue { Start = start, Stop = stop, Order = order };
        }
    }
    public class SortedSetRangeByScoreMessage : EMRedisMessage
    {
        public SortedSetRangeByScoreMessage(string key, double scoreStart, double scoreStop, Exclude exclude, Order order, long skip = 0, long take = -1)
        {
            this.Key = key;
            this.SortedSetValue = new EMSortedSetValue { ScoreStart = scoreStart, ScoreStop = scoreStop, Order = order, Exclude = exclude, Skip = skip, Take = take };
        }
    }
    public class SortedSetRemoveMessage : EMRedisMessage
    {
        public SortedSetRemoveMessage(string key, RedisValue member)
        {
            this.Key = key;
            this.SortedSetValue = new EMSortedSetValue { Member = member };
        }
    }

    #endregion

    #region HyperLogLog

    public class EMHyperLogLogValue
    {
        public RedisValue Value { get; set; }
        public RedisValue[] Values { get; set; }
        public RedisKey[] Keys { get; set; }
        public RedisKey Destination { get; set; }
        public RedisKey First { get; set; }
        public RedisKey Second { get; set; }
    }
    public class HyperLogLogAddMessage : EMRedisMessage
    {
        public HyperLogLogAddMessage(RedisKey key, RedisValue value)
        {
            this.Key = key;
            this.HyperLogLogValue = new EMHyperLogLogValue { Value = value };
        }
    }
    public class HyperLogLogAddArrayMessage : EMRedisMessage
    {
        public HyperLogLogAddArrayMessage(RedisKey key, RedisValue[] values)
        {
            this.Key = key;
            this.HyperLogLogValue = new EMHyperLogLogValue { Values = values };
        }
    }
    public class HyperLogLogLengthMessage : EMRedisMessage
    {
        public HyperLogLogLengthMessage(RedisKey key)
        {
            this.Key = key;
        }
    }
    public class HyperLogLogLengthArrayMessage : EMRedisMessage
    {
        public HyperLogLogLengthArrayMessage(RedisKey[] keys)
        {
            this.Key = keys.FirstOrDefault();
            this.HyperLogLogValue = new EMHyperLogLogValue { Keys = keys };
        }
    }
    public class HyperLogLogMergeMessage : EMRedisMessage
    {
        public HyperLogLogMergeMessage(RedisKey destination, RedisKey first, RedisKey second)
        {
            this.Key = destination;
            this.HyperLogLogValue = new EMHyperLogLogValue { Destination = destination, First = first, Second = second }; ;
        }
    }
    public class HyperLogLogMergeArrayMessage : EMRedisMessage
    {
        public HyperLogLogMergeArrayMessage(RedisKey destination, RedisKey[] sourceKeys)
        {
            this.Key = destination;
            this.HyperLogLogValue = new EMHyperLogLogValue { Destination = destination, Keys = sourceKeys };
        }
    }

    #endregion

    #region Bitmaps

    public class EMBitValue
    {
        public Bitwise Operation { get; set; }
        public RedisKey Destination { get; set; }
        public RedisKey First { get; set; }
        public RedisKey Second { get; set; }
        public RedisKey[] Keys { get; set; }

        public bool Bit { get; set; }
        public long Offset { get; set; }

        public long Start { get; set; }
        public long End { get; set; }
    }
    public class StringBitCountMessage : EMRedisMessage
    {
        public StringBitCountMessage(RedisKey key, long start, long end)
        {
            this.Key = key;
            this.BitValue = new EMBitValue { Start = start, End = end };
        }
    }
    public class StringBitOperationMessage : EMRedisMessage
    {
        public StringBitOperationMessage(RedisKey destination, Bitwise operation, RedisKey first, RedisKey second)
        {
            this.Key = destination;
            this.BitValue = new EMBitValue { Operation = operation, Destination = destination, First = first, Second = second };
        }
    }
    public class StringBitOperationArrayMessage : EMRedisMessage
    {
        public StringBitOperationArrayMessage(RedisKey destination, Bitwise operation, RedisKey[] keys)
        {
            this.Key = destination;
            this.BitValue = new EMBitValue { Operation = operation, Destination = destination, Keys = keys };
        }
    }
    public class StringBitPositionMessage : EMRedisMessage
    {
        public StringBitPositionMessage(RedisKey key, bool bit, long start, long end)
        {
            this.Key = key;
            this.BitValue = new EMBitValue { Bit = bit, Start = start, End = end };
        }
    }
    public class StringGetBitMessage : EMRedisMessage
    {
        public StringGetBitMessage(RedisKey key, long offset)
        {
            this.Key = key;
            this.BitValue = new EMBitValue { Offset = offset };
        }
    }
    public class StringSetBitMessage : EMRedisMessage
    {
        public StringSetBitMessage(RedisKey key, bool bit, long offset)
        {
            this.Key = key;
            this.BitValue = new EMBitValue { Bit = bit, Offset = offset };
        }
    }

    #endregion
}
